/*
 * @copyright (c) 2024, MacRsh
 *
 * @license SPDX-License-Identifier: Apache-2.0
 *
 * @date 2024-02-18    MacRsh       First version
 */

#ifndef _MODULE_H_
#define _MODULE_H_

#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <malloc.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/**
 * @addtogroup Compiler
 * @{
 */
#if defined(__ARMCC_VERSION)
#define MODULE_SECTION(x)           __attribute__((section(x))) /**< Section */
#define MODULE_USED                 __attribute__((used))       /**< Used */
#define MODULE_WEAK                 __attribute__((weak))       /**< Weak */
typedef int ssize_t;                                            /**< ssize_t type */
#elif defined (__IAR_SYSTEMS_ICC__)
#define MODULE_SECTION(x)           @ x                         /**< Section */
#define MODULE_USED                 __root                      /**< Used */
#define MODULE_WEAK                 __weak                      /**< Weak */
#elif defined (__GNUC__)
#define MODULE_SECTION(x)           __attribute__((section(x))) /**< Section */
#define MODULE_USED                 __attribute__((used))       /**< Used */
#define MODULE_WEAK                 __attribute__((weak))       /**< Weak */
#elif defined (__ADSPBLACKFIN__)
#define MODULE_SECTION(x)           __attribute__((section(x))) /**< Section */
#define MODULE_USED                 __attribute__((used))       /**< Used */
#define MODULE_WEAK                 __attribute__((weak))       /**< Weak */
#elif defined (__TASKING__)
#define MODULE_SECTION(x)           __attribute__((section(x))) /**< Section */
#define MODULE_USED                 \
    __attribute__((used, protect))                              /**< Used */
#define MODULE_WEAK                 __attribute__((weak))       /**< Weak */
#else
#define MODULE_SECTION(x)           __attribute__((section(x))) /**< Section */
#define MODULE_USED                 __attribute__((used))       /**< Used */
#define MODULE_WEAK                 __attribute__((weak))       /**< Weak */
#endif /* __ARMCC_VERSION */
/** @} */

/**
 * @addtogroup Module-export
 * @{
 */
typedef void (*module_export_fn_t)(void);                         /**< Module export function */

/**
 * This macro defines the export function of module.
 *
 * @param _fn The function.
 * @param _level The call priority level (1~256).
 *
 * @note The level must be greater than or equal to 1 and smaller than 256.
 *
 * @example Example of module export function:
 *          void module_export_example(void)
 *          {
 *              printf("Hello, World!\n");
 *          }
 *          MODULE_EXPORT(module_export_example, "1");
 */
#define MODULE_EXPORT(_fn, _level) \
    MODULE_USED const module_export_fn_t _module_export_##_fn MODULE_SECTION("module_export."_level) = _fn

void module_export_handle(void);
/** @} */

/**
 * @addtogroup Module
 * @{
 */

/**
 * This structure defines the resource of module.
 */
struct module_resource
{
    const void *ops;                                            /**< Operation */
    void *data;                                                 /**< Data */
};

struct module;

/**
 * This structure defines the operation of module.
 */
struct module_ops
{
    int (*init)(struct module *module);
    int (*deinit)(struct module *module);
    int (*ioctl)(struct module *module, int pos, int cmd, void *args);
    ssize_t (*input)(struct module *module, int pos, void *buf, size_t count);
    ssize_t (*output)(struct module *module, int pos, const void *buf, size_t count);
};

/**
 * This structure defines the reference of module.
 */
struct reference
{
    struct module *module;                                      /**< Module */
    struct reference *next;                                     /**< Next */
};

/**
 * This structure defines module.
 */
struct module
{
    const char *name;                                           /**< Name */
    size_t ref;                                                 /**< Reference count */
    struct
    {
        struct module *prev;                                    /**< Previous */
        struct module *next;                                    /**< Next */
    } public;                                                   /**< Public */
    struct module_resource *resource;                           /**< Resource */
    const struct module_ops *ops;                               /**< Operation */
    int pos;                                                    /**< Position */
    struct
    {
        struct reference input;                                 /**< Input reference */
        struct reference output;                                /**< Output reference */
    } io;                                                       /**< I/O */
};

/**
 * This macro defines the operator I/O control command.
 *
 * @param _io The input/output control.
 * @param _tier The module level that the command targets.
 * @param _cmd The control command.
 */
#define MODULE_IOCTL(_io, _tier, _cmd) \
    (0x90000000 | ((_io & 0x1) << 24) | \
    ((_tier & 0xff) << 16) | \
    (_cmd & 0xffff))                                            /**< I/O control command */

/**
 * This macro defines the module seek mode.
 */
#define MODULE_SEEK_SET           (0)                           /**< Start position */
#define MODULE_SEEK_CUR           (1)                           /**< Current position */
#define MODULE_SEEK_END           (2)                           /**< End position */

struct module *module_find(const char *name);
int module_init(struct module *module,
                const char *name,
                struct module_resource *resource,
                const struct module_ops *ops);
struct module_resource *module_get_resource(struct module *module);
int module_public(struct module *module);
int module_unpublic(struct module *module);
int module_load_input(struct module *module, struct module *input);
int module_load_output(struct module *module, struct module *output);
int module_unload_input(struct module *module, struct module *input);
int module_unload_output(struct module *module, struct module *output);
ssize_t module_read(struct module *module, void *buf, size_t count);
ssize_t module_write(struct module *module, const void *buf, size_t count);
int module_ioctl(struct module *module, int cmd, void *args);
int module_seek(struct module *module, int offset, int whence);
/** @} */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* _MODULE_H_ */
